#include "dht11.h"
#include "FreeRTOS.h"
#include "task.h"
#include "time_delay.h"

#define Delay_ms(ms)   time_delay_ms(ms)
#define Delay_us(us)   time_delay_us(us)

#define __GPIO_INIT(DHT11)              {   GPIO_InitTypeDef GPIO_InitStructure; \
                                            GPIO_InitStructure.GPIO_Mode        = GPIO_Mode_OUT; \
                                            GPIO_InitStructure.GPIO_PuPd        = GPIO_PuPd_UP; \
                                            GPIO_InitStructure.GPIO_Speed       = GPIO_Speed_50MHz; \
                                            GPIO_InitStructure.GPIO_OType       = GPIO_OType_PP; \
                                            GPIO_InitStructure.GPIO_Pin         = DHT11->gpio_pin; \
                                            GPIO_Init(DHT11->gpio_port,&GPIO_InitStructure);    }

#define __GPIO_CONFIG_OUT_PP(DHT11)     {   GPIO_InitTypeDef GPIO_InitStructure; \
                                            GPIO_InitStructure.GPIO_Mode        = GPIO_Mode_OUT; \
                                            GPIO_InitStructure.GPIO_PuPd        = GPIO_PuPd_UP; \
                                            GPIO_InitStructure.GPIO_Speed       = GPIO_Speed_50MHz; \
                                            GPIO_InitStructure.GPIO_OType       = GPIO_OType_PP; \
                                            GPIO_InitStructure.GPIO_Pin         = DHT11->gpio_pin; \
                                            GPIO_Init(DHT11->gpio_port,&GPIO_InitStructure);    }

#define __GPIO_CONFIG_IPU(DHT11)        {   GPIO_InitTypeDef GPIO_InitStructure; \
                                            GPIO_InitStructure.GPIO_Mode        = GPIO_Mode_IN; \
                                            GPIO_InitStructure.GPIO_PuPd        = GPIO_PuPd_UP; \
                                            GPIO_InitStructure.GPIO_Speed       = GPIO_Speed_50MHz; \
                                            GPIO_InitStructure.GPIO_OType       = GPIO_OType_PP; \
                                            GPIO_InitStructure.GPIO_Pin         = DHT11->gpio_pin; \
                                            GPIO_Init(DHT11->gpio_port,&GPIO_InitStructure);    }

#define __GPIO_SET_IO(DHT11,Status)    {Status?GPIO_SetBits(DHT11->gpio_port,DHT11->gpio_pin):GPIO_ResetBits(DHT11->gpio_port,DHT11->gpio_pin);}

#define __GPIO_IO_H(DHT11)  {__GPIO_SET_IO(DHT11,1)}
#define __GPIO_IO_L(DHT11)  {__GPIO_SET_IO(DHT11,0)}

#define __GPIO_READ_IO(DHT11)   ( GPIO_ReadInputDataBit(DHT11->gpio_port,DHT11->gpio_pin) )

static void dht11_reset(DHT11_t px_dht)
{
    __GPIO_CONFIG_OUT_PP(px_dht);

    __GPIO_IO_L(px_dht);
    Delay_ms(20);
    __GPIO_IO_H(px_dht);
    Delay_us(30);

    __GPIO_CONFIG_IPU(px_dht);
}

static int dht11_waitreceive(DHT11_t px_dht)
{
    int wait_time = 0;

    while (__GPIO_READ_IO(px_dht) && wait_time<100)
    {
        wait_time++;
        Delay_us(1);
    }

    if(wait_time>=100)
        return -1;
    else
        wait_time = 0;
    
    while (!__GPIO_READ_IO(px_dht) && wait_time <100)
    {
        wait_time++;
        Delay_us(1);
    }

    if(wait_time>=100)
        return -2;
    else
        return 0;
}

static uint8_t dht11_readbyte(DHT11_t px_dht)
{
    uint8_t data = 0,i;
    uint8_t ret;
    for(i = 0;i<8;i++)
    {
        ret = dht11_waitreceive(px_dht);
        
        Delay_us(40);
        
        if(__GPIO_READ_IO(px_dht))
        {
            data |= (0x80>>i);
        }
    }
    return data;
}


int dht_receive_data(DHT11_t px_dht)
{
    uint8_t rev_data[5],i;
    int ret;
    
    dht11_reset(px_dht);
    
    ret = dht11_waitreceive(px_dht);
    if(ret == 0)
    {
        for(i = 0;i<5;i++)
        {   
            rev_data[i] = dht11_readbyte(px_dht);
        }
        if((rev_data[0]+rev_data[1]+rev_data[2]+rev_data[3]) == rev_data[4])
        {
            px_dht->humidity = rev_data[0];
            px_dht->temperature = rev_data[2];    
            return 0;
        }
    }
    return 1;
}
                                
int dht11_init(DHT11_t px_dht,GPIO_TypeDef* GPIOx,uint32_t GPIO_Pin)
{
    if(GPIOx == GPIOA){RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);}
    else if(GPIOx == GPIOB){RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);}
    else if(GPIOx == GPIOC){RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);}
    else if(GPIOx == GPIOD){RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);}
    else if(GPIOx == GPIOE){RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);}
    else if(GPIOx == GPIOF){RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);}
    else if(GPIOx == GPIOG){RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG,ENABLE);}
    
    px_dht->gpio_port = GPIOx;
    px_dht->gpio_pin = GPIO_Pin;
    px_dht->humidity = 0.0;
    px_dht->temperature = 0.0;

    __GPIO_INIT(px_dht);

    __GPIO_IO_H(px_dht);

    dht11_reset(px_dht);
    
    return dht11_waitreceive(px_dht);        
}
